﻿using System.Security.Claims;
using Devonline.Core;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Logging;

namespace Devonline.CloudService.Tencent.Weixin;

/// <summary>
/// 微信公众平台接入接口
/// </summary>
/// <param name="logger"></param>
/// <param name="endpoint">微信服务器接口配置</param>
/// <param name="httpContextAccessor"></param>
/// <param name="cache"></param>
/// <param name="httpClientFactory">http client 工厂, 需要在全局配置微信服务器接口地址</param>
public class MiniProgramService(
    ILogger<MiniProgramService> logger,
    IMiniProgramEndpoint endpoint,
    IHttpContextAccessor httpContextAccessor,
    IDistributedCache cache,
    IHttpClientFactory httpClientFactory
    ) : MediaPlatformService(logger, endpoint, httpContextAccessor, cache, httpClientFactory), IMiniProgramService, IMediaPlatformService, IWeixinService
{
    /// <summary>
    ///小程序 SessionKeyAuthorizeAsync
    /// docs:
    /// miniprogram: https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/user-login/code2Session.html
    /// </summary>
    /// <param name="code">code</param>
    /// <returns></returns>
    public virtual async Task SessionKeyAuthorizeAsync(string code)
    {
        var url = $"sns/jscode2session?appid={_endpoint.AppId}&secret={_endpoint.Secret}&js_code={code}&grant_type=authorization_code";
        using var httpClient = _httpClientFactory.CreateClient(nameof(WeixinService));
        var response = await httpClient.GetStringAsync(url);

        try
        {
            GetWeixinResponse(response);
            var sessionKey = response.ToJsonObject<WeixinSessionKey>();
            if (sessionKey is null || sessionKey.ErrCode != 0 || string.IsNullOrWhiteSpace(sessionKey.SessionKey))
            {
                throw new Exception("登录凭证校验失败, 服务器返回详情: " + response);
            }

            _logger.LogDebug("session Key 获取成功!");
            var claims = new List<Claim>();
            claims.Add(new Claim(AppSettings.CLAIM_TYPE_JWT_SUBJECT, sessionKey.OpenId));
            claims.Add(new Claim(AppSettings.CLAIM_TYPE_OPEN_ID, sessionKey.OpenId));
            string scheme = CookieAuthenticationDefaults.AuthenticationScheme;
            var claimsPrincipal = new ClaimsPrincipal(new ClaimsIdentity(claims, scheme));
            await _httpContext.SignInAsync(scheme, claimsPrincipal, new AuthenticationProperties { IsPersistent = true, Items = { { nameof(scheme), nameof(AuthType.Weixin) } } });
            _httpContext.User = claimsPrincipal;
        }
        catch (Exception ex)
        {
            throw new Exception("登录凭证校验失败, 错误信息: " + ex.GetMessage(), ex);
        }
    }
}